package com.jasperframework.boot.common.utils;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

/**
  * <p>  </p>
  *
  * @site https://miliqkdoc.motopa.cn/
  * @author daizhao
  * @date 2022/12/12 12:12
  */
public class DesUtil {

	public static final String CRYPT_KEY = "*(Xd$tb1"; //指定8位数的密钥   *(Xd$tb1

	private final static String DES_ALGORITHM_MODE = "DES/CBC/PKCS5Padding"; // 算法模式：算法/模式/补码方式
	private final static String ALGORITHM = "DES"; // 算法

	private static final Logger logger = LoggerFactory.getLogger(DesUtil.class);

	/**
	 *  @Author daizhao
	 *  @Date 2018-4-2 14:04
	 *  @Params []
	 *  @Return byte[]
	 *  @Info 生成DES算法密钥
	 */
	public static String generateKey() throws NoSuchAlgorithmException {
		// DES算法要求有一个可信任的随机数源
		SecureRandom sr = new SecureRandom();
		// 生成一个DES算法的KeyGenerator对象
		KeyGenerator kg = KeyGenerator.getInstance(ALGORITHM);
		kg.init(sr);
		// 生成密钥
		SecretKey secretKey = kg.generateKey();
		// 获取密钥数据
		byte[] key = secretKey.getEncoded();
		return BASE64Utils.getEncodeBase64(key);
	}

	/**
	 * 根据字符串创建DES秘钥
	 * @param key
	 * @return 自定义字符串的DES秘钥
	 * @throws Exception
	 */
	public static String getDESKey(String key) throws Exception {
		// 创建 DES 密钥
		byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8);
		DESKeySpec desKeySpec = new DESKeySpec(keyBytes);
		SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
		SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
		return BASE64Utils.getEncodeBase64(secretKey.getEncoded());
	}

	/**
	 * 加密
	 * @param content	 待加密的内容
	 * @param encryptKey 加密秘钥
	 * @return
	 * @throws Exception
	 */
	public static String encryptDES(String content, String encryptKey) throws Exception {
		//将密钥解密
		byte[] encryptBytes = BASE64Utils.decodeBase64(encryptKey);
		IvParameterSpec zeroIv = new IvParameterSpec(new byte[8]);
		// 生成一个DES算法的KeyGenerator对象
		SecretKeySpec key = new SecretKeySpec(encryptBytes, ALGORITHM);
		Cipher cipher = Cipher.getInstance(DES_ALGORITHM_MODE);
		cipher.init(Cipher.ENCRYPT_MODE, key, zeroIv);
		byte[] encryptedData = cipher.doFinal(content.getBytes());
		return BASE64Utils.getEncodeBase64(encryptedData);
	}

	/**
	 * 加密
	 * @param content		待加密的内容
	 * @param desKey		加密秘钥
	 * @param iv			iv 偏移量字符串增加数据的安全性
	 * @return
	 * @throws Exception
	 */
	public static String encryptDES(String content, String desKey, String iv) throws Exception {
		//将密钥解密
		byte[] encryptBytes = BASE64Utils.decodeBase64(desKey);
		// 生成一个DES算法的KeyGenerator对象
		SecretKeySpec key = new SecretKeySpec(encryptBytes, ALGORITHM);
		IvParameterSpec zeroIv = new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8));
		Cipher cipher = Cipher.getInstance(DES_ALGORITHM_MODE);
		cipher.init(Cipher.ENCRYPT_MODE, key, zeroIv);
		byte[] encryptedData = cipher.doFinal(content.getBytes());
		return BASE64Utils.getEncodeBase64(encryptedData);
	}

	/**
	 * 解密
	 * @param encryptString		密文
	 * @param desKey			加密秘钥
	 * @return
	 * @throws Exception
	 */
	public static String decryptDES(String encryptString, String desKey) throws Exception {
		//将密钥解密
		byte[] decryptBytes = BASE64Utils.decodeBase64(desKey);
		byte[] byteMi = BASE64Utils.decodeBase64(encryptString);
		IvParameterSpec zeroIv = new IvParameterSpec(new byte[8]);
		SecretKeySpec key = new SecretKeySpec(decryptBytes, ALGORITHM);
		Cipher cipher = Cipher.getInstance(DES_ALGORITHM_MODE);
		cipher.init(Cipher.DECRYPT_MODE, key, zeroIv);
		byte[] decryptedData = cipher.doFinal(byteMi);
		return new String(decryptedData, StandardCharsets.UTF_8);
	}

	/**
	 * 解密
	 * @param encryptString		密文
	 * @param desKey			加密秘钥
	 * @param iv				iv 偏移量字符串增加数据的安全性
	 * @return
	 * @throws Exception
	 */
	public static String decryptDES(String encryptString, String desKey, String iv) throws Exception {
		//将密钥解密
		byte[] decryptBytes = BASE64Utils.decodeBase64(desKey);
		byte[] byteMi = BASE64Utils.decodeBase64(encryptString);
		IvParameterSpec zeroIv = new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8));
		SecretKeySpec key = new SecretKeySpec(decryptBytes, ALGORITHM);
		Cipher cipher = Cipher.getInstance(DES_ALGORITHM_MODE);
		cipher.init(Cipher.DECRYPT_MODE, key, zeroIv);
		byte[] decryptedData = cipher.doFinal(byteMi);
		return new String(decryptedData, StandardCharsets.UTF_8);
	}

	/**
	 * 动态生成密钥对的Sample
	 * @param content
	 */
	private static void autoGenerateKey(String content){
		try {
			String desKey = generateKey();
			System.out.println("desKey：" + desKey);
			String encryptStr = encryptDES(content, desKey);
			String decryptStr = decryptDES(encryptStr, desKey);
			System.out.println("encryptStr："+ encryptStr);
			System.out.println("decryptStr："+ decryptStr);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 根据自定义字符串生成秘钥对
	 * @param content	待加密的内容
	 * @param keyStr	自定义秘钥字符串
	 */
	private static void customGenerateKey(String content, String keyStr){
		try {
			String desKey = StringUtils.isNotBlank(keyStr) ? getDESKey(keyStr) : BASE64Utils.getDecodeBase64(CRYPT_KEY, "");
			System.out.println("desKey：" + desKey);
			String encryptStr = encryptDES(content, desKey);
			String decryptStr = decryptDES(encryptStr, desKey);
			System.out.println("encryptStr："+ encryptStr);
			System.out.println("decryptStr："+ decryptStr);
			generateKey();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 根据自定义字符串、iv 生成秘钥对
	 * @param content   待加密的内容
	 * @param keyStr	自定义秘钥字符串
	 * @param ivStr		ivStr 偏移量字符串增加数据的安全性
	 */
	private static void customGenerateKey(String content, String keyStr, String ivStr){
		try {
			String desKey = StringUtils.isNotBlank(keyStr) ? getDESKey(keyStr) : BASE64Utils.getDecodeBase64(CRYPT_KEY, "");
			System.out.println("desKey：" + desKey);
			String encryptStr = encryptDES(content, desKey, ivStr);
			String decryptStr = decryptDES(encryptStr, desKey, ivStr);
			System.out.println("encryptStr："+ encryptStr);
			System.out.println("decryptStr："+ decryptStr);
			generateKey();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static void main(String[] args) throws Exception {

		String content = "hello";
		System.out.println("====================[自动生成秘钥对]====================");
		autoGenerateKey(content);
		System.out.println("====================[根据自定义字符串生成秘钥对]====================");
		customGenerateKey(content, "1234567890123456");
		System.out.println("====================[根据自定义字符串、iv 生成秘钥对]====================");
		customGenerateKey(content, "1234567890123456", "12345678");


	}
}
